using GLib;
using Gtk;


/** A GtkTreeModel (not hierarchic) made with Gio*/
public class Giocmd.FileModel : GLib.Object, Gtk.TreeModel, Gtk.TreeSortable
{
	private List<PanelFile> files;
	private int stamp;
	private int n_columns = 2;
	private CompareFunc[] compare_funcs;
	private int sort_column = 0;
	private SortType order = SortType.ASCENDING;
	
	public File current_directory {get;construct;}
	
	public FileModel (File current_directory)
	{
		GLib.Object(current_directory: current_directory);
	}
	
	construct {
		this.stamp = 5;
		this.files = new List<PanelFile>();
		compare_funcs = new CompareFunc[] {(CompareFunc)PanelFile.NameCompareFunc,(CompareFunc)PanelFile.SizeCompareFunc};
		//create a PanelFile for ".."
		FileInfo fileInfo = current_directory.resolve_relative_path ("..").query_info ( "standard::*", FileQueryInfoFlags.NOFOLLOW_SYMLINKS, null );
		bool firstFile = true;
		FileEnumerator enumerator = current_directory.enumerate_children ("*", FileQueryInfoFlags.NONE, null);
		do {
			PanelFile panelFile = new PanelFile (fileInfo);
			panelFile.parent_directory_link = firstFile;
			firstFile = false;
			files.insert_sorted (panelFile, compare_funcs[sort_column]);
		} while (null != (fileInfo = enumerator.next_file (null)));
	}
	
	public PanelFile get_file (TreePath path)
	{
		TreeIter iter;
		PanelFile panelFile;
		get_iter (out iter, path);
		panelFile = iter.user_data as PanelFile;

		return panelFile;
	}
	
	///TreeSortable implementation
	
	public bool get_sort_column_id (out int sort_column_id, out Gtk.SortType order)
	{
		//message ("get_sort_column_id");
		sort_column_id = this.sort_column;
		if (&order != null)
		{
			order = this.order;
		}
		return true;
	}
	public bool has_default_sort_func () 
	{
		//message ("has_default_sort_func called");
		return false;
	}
	public void set_default_sort_func (owned Gtk.TreeIterCompareFunc sort_func)
	{
		//message ("set_default_sort_func not supported");
	}
	public void set_sort_column_id (int sort_column_id, Gtk.SortType order)
	{
		//message ("set_sort_column_id");
		if ( 0 <= sort_column_id && sort_column_id < n_columns) {
			sort_column = sort_column_id;
			files.sort ( compare_funcs[sort_column] );
			sort_column_changed ();	
		}
	}
	public void set_sort_func (int sort_column_id, owned Gtk.TreeIterCompareFunc sort_func)
	{
		//message ("set sort function called");
	}
	
	///TreeModel implementation
	
	public GLib.Type get_column_type (int index_){
		return typeof (string);	
	}
	
	public Gtk.TreeModelFlags get_flags (){
		Gtk.TreeModelFlags flags = TreeModelFlags.LIST_ONLY | TreeModelFlags.ITERS_PERSIST;
		return flags;
	}
	
	/**
	 * Given a path, creates an iter
	 */	 	
	public bool get_iter (out Gtk.TreeIter iter, Gtk.TreePath path){
		int depth = path.get_depth ();
		assert (depth == 1);
		int n = path.get_indices ()[0];
		assert (n >= 0 && n < files.length () );
		PanelFile file = files.nth_data (n);
		
		iter.stamp = this.stamp;
		iter.user_data = file;
		iter.user_data2 = null;
		iter.user_data3 = null;
		return true;
	}
	
	public int get_n_columns (){
		return n_columns;
	}
	
	/** 
	 * Given an iter, returns a path
	 */	 	
	public Gtk.TreePath get_path (Gtk.TreeIter iter){
		assert (iter.user_data != null);
		PanelFile file = iter.user_data as PanelFile;
		
		TreePath path = new TreePath();
		int pos = files.index (file);
		assert (pos != -1);
		path.append_index (pos);
		return path;
	}
	
	public void get_value (Gtk.TreeIter iter, int column, ref GLib.Value value){
		assert (iter.user_data != null);
		PanelFile file = iter.user_data as PanelFile;
		value = Value (typeof(string));
		switch (column) {
			case 0:
				if (file.directory) {
					value.set_string ("[" + file.name + "]");
				} else {
					value.set_string (file.name);
				}
				break;
			case 1: 
				if (file.directory) {
					value.set_string ("<DIR>");
				} else {
					value.set_string (file.size.to_string ());
				}
				break;
		}		
	}
	
	/**
	 * Should never be reached since iter_has_child is never true
	 */	 	
	public bool iter_children (out Gtk.TreeIter iter, Gtk.TreeIter? parent){
		assert_not_reached ();
	}
	
	/** 
	 * always false since this is a list
	 */	 	
	public bool iter_has_child (Gtk.TreeIter iter){
		return false;
	}
	
	/**
	 * Number of children for an iter: treated only the special case,
	 * where iter == null, returns the number of elements in the list
	 */	 	  	
	public int iter_n_children (Gtk.TreeIter? iter){
		if (iter == null) {
			uint n_children = files.length ();
			return (int)n_children;
		} else {
			return 0;
		}
	}
	
	/** 
	 * Given an iter, modify it to point to the next file
	 */	 	
	public bool iter_next (ref Gtk.TreeIter iter){
		assert (iter.user_data != null);
		PanelFile file = iter.user_data as PanelFile;
		weak List node = files.find (file);
		if ((node != null) && (node.next != null))
		{
			iter.stamp = this.stamp;
			iter.user_data = node.next.data;
			return true;
		} else {
			return false;
		}
		return false;		
	}
	
	public bool iter_nth_child (out Gtk.TreeIter iter, Gtk.TreeIter? parent, int n)
	{
		if (parent == null)
			return false;
		if (n<0 || n>= files.length ())
			return false;
		iter.stamp = this.stamp;
		iter.user_data = files.nth_data (n);
		return true;
	}

	/**  
	 * again, not implemented since this is not a tree
	 */
	public bool iter_parent (out Gtk.TreeIter iter, Gtk.TreeIter child){
		return false;
	}
	
	/**
	 * hmm somethinkg should be bookkept here ..
	 */	 	
	public void ref_node (Gtk.TreeIter iter){
		
	}
	
	/**
	 * .. and here
	 */	 	
	public void unref_node (Gtk.TreeIter iter){
		
	}
}
